package cn.com.jdyun.service.impl;

import cn.com.jdyun.exception.BdexGatewayException;
import cn.com.jdyun.mapper.ext.ExtSysConfigLogMapper;
import cn.com.jdyun.mapper.ext.ExtSysConfigMapper;
import cn.com.jdyun.pojo.SysConfig;
import cn.com.jdyun.pojo.SysConfigLog;
import cn.com.jdyun.service.SysConfigService;
import cn.com.jdyun.util.ConfigParam;
import cn.com.jdyun.util.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Service
public class SysConfigServiceImpl implements SysConfigService {

    private static final Logger logger = LoggerFactory.getLogger(SysConfigServiceImpl.class);

    @Autowired
    private ExtSysConfigMapper sysConfigMapper;
    @Autowired
    private ExtSysConfigLogMapper sysConfigLogMapper;
    @Autowired
    private RedisUtil redisUtil;

    //创建一个可重用固定线程数的线程池
    private static final ExecutorService pool = Executors.newSingleThreadExecutor();

    @Transactional(readOnly = true)
    @Override
    public String queryConfigInitValue(ConfigParam code) throws BdexGatewayException {
        String watchkey = code.name();
        SysConfig config = sysConfigMapper.selectByCode(watchkey);
        String initValue = config.getInitValue();
        redisUtil.set(watchkey, initValue);
        return initValue;
    }

    @Transactional(readOnly = true)
    @Override
    public List<SysConfig> getConfigParams() {
        return sysConfigMapper.selectAll();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String changeConfigValue(ConfigParam code, String amount, String userId) throws BdexGatewayException {
        Jedis jedis = redisUtil.getResource();
        String watchkey = code.name();

        String poolAmount = null;
        BigDecimal lastValue = null;
        while (true) {
            jedis.watch(watchkey);// watchkey
            poolAmount = jedis.get(watchkey);
            if (poolAmount == null) {
                SysConfig config = sysConfigMapper.selectByCode(watchkey);
                poolAmount = config.getInitValue();
                if (poolAmount == null) {
                    throw new BdexGatewayException("请先初始化矿池");
                }
            }
            lastValue = new BigDecimal(poolAmount).add(new BigDecimal(amount)).setScale(6, BigDecimal.ROUND_HALF_DOWN);
            if (lastValue.doubleValue() < 0) {
                throw new BdexGatewayException("矿池余额不足");
            }
            Transaction tx = jedis.multi();// 开启事务
            tx.set(watchkey, lastValue.toString());
            List<Object> list = tx.exec();// 提交事务，如果此时watchkey被改动了，则返回null
            if (list != null && !list.isEmpty()) {
                break;
            }
            try {
                Thread.sleep(100); //如果失败，暂停100ms;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        jedis.close();
        if (lastValue == null) {
            lastValue = BigDecimal.valueOf(0);
        } else {
            final String p1 = poolAmount;
            final String p2 = lastValue.toString();
            final String p3 = userId;
            pool.execute(() -> {
                try {
                    //新增矿池修改记录
                    updateConfigInitValue(code, p1, p2, p3);
                } catch (Exception e) {
                    logger.error(e.getMessage());
                }
            });
        }
        return lastValue.toString();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void initParameterValues(String code, String codeName, String initValue, String operatorId) throws BdexGatewayException {
        //查询是否已存在
        SysConfig sysConfig1 = sysConfigMapper.selectByCode(code);
        if(sysConfig1!=null){
            throw new BdexGatewayException("该参数配置已存在!");
        }
        SysConfig sysConfig = new SysConfig();
        sysConfig.setCode(code);
        sysConfig.setCodeName(codeName);
        sysConfig.setInitValue(initValue);
        sysConfig.setOperatorId(operatorId);
        sysConfig.setCreateTime(new Date());
        sysConfig.setUpdateTime(new Date());
        //新增一条系统配置项
        int result = sysConfigMapper.insert(sysConfig);
        if(result<=0){
            throw new BdexGatewayException("新增系统配置项失败!");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public String updateConfigInitValue(ConfigParam code, String poolAmount, String newValue, String userId) throws BdexGatewayException {
        Date cur = new Date();
        SysConfigLog configLog = new SysConfigLog();
        configLog.setCode(code.name());
        configLog.setCreateTime(cur);
        configLog.setNewValue(newValue);
        configLog.setOperator(userId);

        SysConfig config = sysConfigMapper.selectByCode(code.name());

        if (config == null) {
            config = new SysConfig();
            config.setCreateTime(cur);
        } else {
            configLog.setOldValue(poolAmount);
        }
        config.setUpdateTime(cur);
        config.setCode(code.name());
        config.setCodeName(code.getCodeName());
        config.setInitValue(newValue);
        config.setOperatorId(userId);
        if (config.getId() != null) {
            sysConfigMapper.updateByPrimaryKeySelective(config);
        } else {
            sysConfigMapper.insert(config);
        }
        sysConfigLogMapper.insert(configLog);

        return config.getInitValue();
    }

    /*@Transactional(rollbackFor = Exception.class)
    @Override
    public BigDecimal miningPoolAmount(BigDecimal rate, String userId) throws BdexGatewayException {
        Jedis jedis = redisUtil.getResource();
        String watchkey = ConfigParam.MINER_POOL_AMOUNT.name();

        String poolAmount = null;
        BigDecimal lastValue = null;
        BigDecimal amount = null;
        while (true) {
            jedis.watch(watchkey);// watchkey
            poolAmount = jedis.get(watchkey);
            if (poolAmount == null) {
                SysConfig config = sysConfigMapper.selectByCode(watchkey);
                poolAmount = config.getInitValue();
                if (poolAmount == null) {
                    throw new BdexGatewayException("请先初始化矿池");
                }
            }

            BigDecimal todayAll = new BigDecimal(poolAmount).multiply(rate);

            amount = todayAll.setScale(4, BigDecimal.ROUND_HALF_UP);

            if (amount.doubleValue() <= 0) {
                return amount;
            }

            lastValue = new BigDecimal(poolAmount).subtract(amount);
            if (lastValue.doubleValue() < 0) {
                throw new BdexGatewayException("矿池余额不足");
            }
            Transaction tx = jedis.multi();// 开启事务
            tx.set(watchkey, lastValue.toString());
            List<Object> list = tx.exec();// 提交事务，如果此时watchkey被改动了，则返回null
            if (list != null && !list.isEmpty()) {
                break;
            }
            try {
                Thread.sleep(100); //如果失败，暂停100ms;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        jedis.close();
        if (lastValue != null) {
            final String p1 = poolAmount;
            final String p2 = lastValue.toString();
            final String p3 = userId;
            pool.execute(() -> {
                try {
                    //保存奖励
                    updateConfigInitValue(ConfigParam.MINER_POOL_AMOUNT, p1, p2, p3);
                } catch (Exception e) {
                    logger.error(e.getMessage());
                }
            });
        }
        return amount;
    }*/

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String initConfigValue(String initValue, String userId) throws BdexGatewayException {
        redisUtil.set(ConfigParam.MINER_POOL_AMOUNT.name(), initValue);
        redisUtil.set(ConfigParam.MINER_POOL_AMOUNT_INIT.name(), initValue);
        SysConfig config = sysConfigMapper.selectByCode(ConfigParam.MINER_POOL_AMOUNT.name());
        updateConfigInitValue(ConfigParam.MINER_POOL_AMOUNT, config == null ? null : config.getInitValue(), initValue, userId);
        config = sysConfigMapper.selectByCode(ConfigParam.MINER_POOL_AMOUNT_INIT.name());
        updateConfigInitValue(ConfigParam.MINER_POOL_AMOUNT_INIT, config == null ? null : config.getInitValue(), initValue, userId);
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateParameterValues(SysConfig sysConfig) throws BdexGatewayException {
        if(StringUtils.isEmpty(sysConfig.getCode())){
            throw new BdexGatewayException("参数号不能为空!");
        }
        if(StringUtils.isEmpty(sysConfig.getInitValue())){
            throw new BdexGatewayException("参数初始化值不能为空!");
        }
        //新增一条更新参数日志记录
        Date cur = new Date();
        SysConfigLog configLog = new SysConfigLog();
        configLog.setCode(sysConfig.getCode());
        configLog.setCreateTime(cur);
        configLog.setNewValue(sysConfig.getInitValue());
        configLog.setOperator(sysConfig.getOperatorId());
        SysConfig config = sysConfigMapper.selectByCode(sysConfig.getCode());

        if (config == null) {
            config = new SysConfig();
            config.setCreateTime(cur);
        } else {
            configLog.setOldValue(config.getInitValue());
        }
        sysConfigLogMapper.insert(configLog);

        sysConfig.setUpdateTime(new Date());
        int result = sysConfigMapper.updateParameterValues(sysConfig);
        if(result<=0){
            throw new BdexGatewayException("更新参数失败!");
        }
    }

}
